/**
 * Java RTP Library (jlibrtp)
 * Copyright (C) 2006 Arne Kepp
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jlibrtp;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * RTCP packets for RTP Feedback Messages
 *
 * In line with RFC 4585, this packet currently only supports NACKs
 *
 * @author Arne Kepp
 */
public class RtcpPktRTPFB extends RtcpPkt {
    /** Logger instance. */
    private static final Logger LOGGER =
        Logger.getLogger(RtcpPktRTPFB.class.getName());

    /** If this packet was for a different SSRC */
    protected boolean notRelevant = false;
    /** SSRC we are sending feeback to */
    protected long ssrcMediaSource = -1;
    /** RTP sequence numbers of lost packets */
    protected int PID[];
    /** bitmask of following lost packets, shared index with PID */
    protected int BLP[];

    /**
     * Constructor for RTP Feedback Message
     *
     * @param ssrcPacketSender SSRC of sender, taken from RTPSession
     * @param ssrcMediaSource SSRC of recipient of this message
     * @param FMT the Feedback Message Subtype
     * @param PID RTP sequence numbers of lost packets
     * @param BLP bitmask of following lost packets, shared index with PID
     */
    protected RtcpPktRTPFB(long ssrcPacketSender, long ssrcMediaSource, int FMT, int[] PID, int[] BLP) {
        super.packetType = 205; //RTPFB
        super.itemCount = FMT;
        this.PID = PID;
        this.BLP = BLP;
    }

    /**
     * Constructor that parses a raw packet to retrieve information
     *
     * @param aRawPkt the raw packet to be parsed
     * @param start the start of the packet, in bytes
     * @param rtpSession the session on which the callback interface resides
     */
    protected RtcpPktRTPFB(byte[] aRawPkt, int start, RTPSession rtpSession) {
        if(LOGGER.isLoggable(Level.FINEST)) {
            LOGGER.finest("  -> RtcpPktRTPFB(byte[], int start)");
        }

        rawPkt = aRawPkt;

        if(! super.parseHeaders(start) || packetType != 205 || super.length < 2) {
            if(LOGGER.isLoggable(Level.FINEST)) {
                LOGGER.finest(" <-> RtcpPktRTPFB.parseHeaders() etc. problem");
            }
            super.problem = -205;
        } else {
            //FMT = super.itemCount;

            ssrcMediaSource = StaticProcs.bytesToUIntLong(aRawPkt,8+start);

            if(ssrcMediaSource == rtpSession.ssrc) {
                super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt,4+start);
                int loopStop = super.length - 2;
                PID = new int[loopStop];
                BLP = new int[loopStop];
                int curStart = 12;

                // Loop over Feedback Control Information (FCI) fields
                for(int i=0; i< loopStop; i++) {
                    PID[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart);
                    BLP[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart + 2);
                    curStart += 4;
                }

                rtpSession.rtcpAVPFIntf.RTPFBPktReceived(
                        super.ssrc, super.itemCount, PID, BLP);
            }
        }



        if(LOGGER.isLoggable(Level.FINEST)) {
            LOGGER.finest("  <- RtcpPktRTPFB()");
        }
    }

    /**
     * Encode the packet into a byte[], saved in .rawPkt
     *
     * CompRtcpPkt will call this automatically
     */
    protected void encode() {
        super.rawPkt = new byte[12 + this.PID.length*4];

        byte[] someBytes = StaticProcs.uIntLongToByteWord(super.ssrc);
        System.arraycopy(someBytes, 0, super.rawPkt, 4, 4);
        someBytes = StaticProcs.uIntLongToByteWord(this.ssrcMediaSource);
        System.arraycopy(someBytes, 0, super.rawPkt, 8, 4);

        // Loop over Feedback Control Information (FCI) fields
        int curStart = 12;
        for(int i=0; i < this.PID.length; i++ ) {
            someBytes = StaticProcs.uIntIntToByteWord(PID[i]);
            super.rawPkt[curStart++] = someBytes[0];
            super.rawPkt[curStart++] = someBytes[1];
            someBytes = StaticProcs.uIntIntToByteWord(BLP[i]);
            super.rawPkt[curStart++] = someBytes[0];
            super.rawPkt[curStart++] = someBytes[1];
        }
        writeHeaders();
    }

    /**
     * Get the FMT (Feedback Message Type)
     * @return value stored in .itemcount, same field
     */
    protected int getFMT() {
        return this.itemCount;
    }

    /**
     * Debug purposes only
     */
    protected void debugPrint() {
        LOGGER.finest("->RtcpPktRTPFB.debugPrint() ");
        LOGGER.finest("  ssrcPacketSender: " + super.ssrc + "  ssrcMediaSource: " + ssrcMediaSource);

        if(this.PID != null && this.PID.length < 1) {
            LOGGER.finest("  No Feedback Control Information (FCI) fields");
        }

        for(int i=0; i < this.PID.length; i++ ) {
            LOGGER.finest("  FCI -> PID: " + PID[i] + "  BLP: " + BLP[i]);
        }
        LOGGER.finest("<-RtcpPktRTPFB.debugPrint() ");
    }
}
